﻿using System;
using System.Globalization;
using System.Transactions;
using System.Web.UI;
using System.Web.UI.WebControls;
using DotNetNuke.Modules._2DoTasks.Components;
using DotNetNuke.Modules._2DoTasks.Components.Controllers;
using DotNetNuke.Modules._2DoTasks.Components.Entities;
using DotNetNuke.Modules._2DoTasks.Components.ExceptionHandling;
using DotNetNuke.Modules._2DoTasks.Components.Utils;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.Localization;

namespace DotNetNuke.Modules._2DoTasks
{
    public partial class TaskTimeEntries : _2DoTasksModuleBase
    {
        #region "Properties"

        private Nullable<int> TimeId
        {
            get
            {
                if (ViewState["TaskTimeEntries_TimeId"] != null)
                    return Convert.ToInt32(ViewState["TaskTimeEntries_TimeId"]);
                return null;
            }
            set
            {
                ViewState["TaskTimeEntries_TimeId"] = value;
            }
        }

        #endregion "Properties"

        #region "Events"

        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                FillLanguages();
                Messages.ClearMessages();

                //Implement your edit logic for your module
                if (!Page.IsPostBack)
                {
                    if (TaskId.HasValue)
                    {
                        BindTaskTime(TaskId.Value);
                    }
                }
            }
            catch (Exception exc) //Module failed to load
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }

        /// <summary>
        /// Clears the controls for creating updating a time entry
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btn_clearTimeEntry_Click(object sender, EventArgs e)
        {
            ClearTimeEntryControl();
        }

        /// <summary>
        /// Adds/Updates a time entry
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btn_addTimeEntry_Click(object sender, EventArgs e)
        {
            try
            {
                DateTime startDate;
                Nullable<DateTime> endDate;

                using (UnitOfWork uof = new UnitOfWork(PortalId, ModuleId))
                {
                    if (TimeParametersCorrectlyFilled(out startDate, out endDate))
                    {
                        TaskTimeController taskTimeController = new TaskTimeController(uof, TaskId.Value);

                        _TaskTime time = new _TaskTime
                        {
                            Billable = chk_billable.Checked,
                            StartDate = startDate,
                            EndDate = endDate,
                            TaskId = TaskId.Value
                        };

                        using (TransactionScope scope = new TransactionScope())
                        {
                            if (TimeId.HasValue)
                            {
                                time.Id = TimeId.Value;
                                taskTimeController.Update(time);
                            }
                            else
                                taskTimeController.Add(time);

                            scope.Complete();
                        }

                        if (TimeId.HasValue)
                            Messages.ShowSuccess(Localization.GetString("UpdateSuccess", this.LocalResourceFile));
                        else
                            Messages.ShowSuccess(Localization.GetString("AddSuccess", this.LocalResourceFile));

                        ClearTimeEntryControl();
                        FillTaskTimeEntries(uof, taskTimeController);
                    }
                }
            }
            catch (TaskTimeValidationException exc)
            {
                if (exc.StateOfError() == SharedEnum.CrudState.Insert)
                {
                    TaskTimeController.InsertStatus status =
                        (TaskTimeController.InsertStatus)Enum.Parse(typeof(TaskTimeController.InsertStatus), exc.ErrorCode().ToString());

                    switch (status)
                    {
                        case TaskTimeController.InsertStatus.TASKNOTFOUND:
                            Messages.ShowWarning(Localization.GetString("WarningTASKNOTFOUND", this.LocalResourceFile));
                            break;

                        case TaskTimeController.InsertStatus.TIMEISNOTVALID:
                            Messages.ShowWarning(Localization.GetString("WarningTIMEISNOTVALID", this.LocalResourceFile));
                            break;

                        case TaskTimeController.InsertStatus.USERCANNOTMODIFYTASK:
                            Messages.ShowWarning(Localization.GetString("WarningUSERCANNOTMODIFYTASK", this.LocalResourceFile));
                            break;

                        default:
                            Exceptions.LogException(exc);
                            Messages.ShowError(Localization.GetString("ErrorAddTaskTime", this.LocalResourceFile));
                            break;
                    }
                }
                else if (exc.StateOfError() == SharedEnum.CrudState.Update)
                {
                    TaskTimeController.UpdateStatus status =
                        (TaskTimeController.UpdateStatus)Enum.Parse(typeof(TaskTimeController.UpdateStatus), exc.ErrorCode().ToString());

                    switch (status)
                    {
                        case TaskTimeController.UpdateStatus.TASKNOTFOUND:
                            Messages.ShowWarning(Localization.GetString("WarningTASKNOTFOUND", this.LocalResourceFile));
                            break;

                        case TaskTimeController.UpdateStatus.TIMEISNOTVALID:
                            Messages.ShowWarning(Localization.GetString("WarningTIMEISNOTVALID", this.LocalResourceFile));
                            break;

                        case TaskTimeController.UpdateStatus.USERCANNOTMODIFYTASK:
                            Messages.ShowWarning(Localization.GetString("WarningUSERCANNOTMODIFYTASK", this.LocalResourceFile));
                            break;

                        default:
                            Exceptions.LogException(exc);
                            Messages.ShowError(Localization.GetString("ErrorUpdateTaskTime", this.LocalResourceFile));
                            break;
                    }
                }
            }
            catch (Exception exc)
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }

        protected void lst_timeEntries_LayoutCreated(object sender, EventArgs e)
        {
            (lst_timeEntries.FindControl("lt_StartDate") as Literal).Text = Localization.GetString("TitleStartDate", this.LocalResourceFile);
            (lst_timeEntries.FindControl("lt_EndDate") as Literal).Text = Localization.GetString("TitleEndDate", this.LocalResourceFile);
            (lst_timeEntries.FindControl("lt_total") as Literal).Text = Localization.GetString("TitleTotal", this.LocalResourceFile);
            (lst_timeEntries.FindControl("lt_CreatedBy") as Literal).Text = Localization.GetString("TitleCreatedBy", this.LocalResourceFile);
            (lst_timeEntries.FindControl("lt_Billable") as Literal).Text = Localization.GetString("TitleBillable", this.LocalResourceFile);
        }

        protected void lst_timeEntries_ItemDataBound(object sender, System.Web.UI.WebControls.ListViewItemEventArgs e)
        {
            if (e.Item.ItemType == ListViewItemType.DataItem)
            {
                var lnk_edit = e.Item.FindControl("lnk_edit") as LinkButton;
                var lnk_delete = e.Item.FindControl("lnk_delete") as LinkButton;

                var curTask = (_TaskTime)e.Item.DataItem;

                if (lnk_edit != null && lnk_delete != null)
                {
                    lnk_edit.CommandArgument = curTask.Id.ToString();
                    lnk_delete.CommandArgument = curTask.Id.ToString();

                    DotNetNuke.UI.Utilities.ClientAPI.AddButtonConfirm(lnk_delete, Localization.GetString("DeleteConfirm", this.LocalResourceFile));
                }
            }
        }

        /// <summary>
        /// Prepares for the edition of a time entry
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void lnkEdit_Click(object sender, EventArgs e)
        {
            try
            {
                using (UnitOfWork uof = new UnitOfWork(PortalId, ModuleId))
                {
                    TaskTimeController taskTimeController = new TaskTimeController(uof, TaskId.Value);
                    _TaskTime taskTime = taskTimeController.Get(Convert.ToInt32((sender as LinkButton).CommandArgument));
                    txt_startDate.Text = taskTime.StartDate.ToString("dd-MM-yyyy");
                    txt_startTime.Text = taskTime.StartDate.ToString("HH:mm");
                    if (taskTime.EndDate.HasValue)
                    {
                        txt_endDate.Text = taskTime.EndDate.Value.ToString("dd-MM-yyyy");
                        txt_endTime.Text = taskTime.EndDate.Value.ToString("HH:mm");
                    }
                    chk_billable.Checked = taskTime.Billable;
                    TimeId = taskTime.Id;
                }
            }
            catch (Exception exc)
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }

        /// <summary>
        /// Deletes the passed task time entry
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void lnkDelete_Click(object sender, EventArgs e)
        {
            try
            {
                using (UnitOfWork uof = new UnitOfWork(PortalId, ModuleId))
                {
                    TaskTimeController taskTimeController = new TaskTimeController(uof, TaskId.Value);
                    _TaskTime taskTime = new _TaskTime { Id = Convert.ToInt32((sender as LinkButton).CommandArgument), TaskId = TaskId.Value };
                    using (TransactionScope scope = new TransactionScope())
                    {
                        taskTimeController.Delete(taskTime);
                        scope.Complete();
                    }
                    FillTaskTimeEntries(uof, taskTimeController);
                    Messages.ShowSuccess(Localization.GetString("DeleteSuccess", this.LocalResourceFile));
                }
            }
            catch (TaskTimeValidationException exc)
            {
                TaskTimeController.DeleteStatus status =
                    (TaskTimeController.DeleteStatus)Enum.Parse(typeof(TaskTimeController.DeleteStatus), exc.ErrorCode().ToString());

                switch (status)
                {
                    case TaskTimeController.DeleteStatus.USERCANNOTMODIFYTASK:
                        Messages.ShowWarning(Localization.GetString("WarningUSERCANNOTMODIFYTASK", this.LocalResourceFile));
                        break;

                    default:
                        Exceptions.LogException(exc);
                        Messages.ShowError(Localization.GetString("ErrorDeleteTaskTime", this.LocalResourceFile));
                        break;
                }
            }
            catch (Exception exc)
            {
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }

        #endregion "Events"

        #region "Aux Functions"

        /// <summary>
        /// Clears the controls for creating/edit a new time entry
        /// </summary>
        private void ClearTimeEntryControl()
        {
            TimeId = null;
            txt_endDate.Text = txt_endTime.Text = txt_startDate.Text = txt_startTime.Text = string.Empty;
            chk_billable.Checked = true;
        }

        /// <summary>
        /// Evaluates if the time entry parameters are correctly filled
        /// </summary>
        /// <returns>returns true if ok, false otherwise</returns>
        private bool TimeParametersCorrectlyFilled(out DateTime out_startDate, out Nullable<DateTime> out_endDate)
        {
            out_startDate = DateTime.Now;
            out_endDate = null;

            if (txt_startDate.Text != string.Empty)
            {
                try
                {
                    CultureInfo provider = CultureInfo.InvariantCulture;

                    out_startDate = DateTime.ParseExact(txt_startDate.Text, "dd-MM-yyyy", provider);
                    if (!txt_startTime.Text.Trim().Equals(string.Empty))
                    {
                        out_startDate = out_startDate.AddMinutes(txt_startTime.Text.GetTotalMinutes());
                    }
                }
                catch (Exception)
                {
                    Messages.ShowWarning(Localization.GetString("ValidationInvalidStartDate", this.LocalResourceFile));
                    return false;
                }
            }
            else
            {
                this.Messages.ShowWarning(Localization.GetString("ValidationRequiredStartDate", this.LocalResourceFile));
                return false;
            }

            if (txt_endDate.Text != string.Empty)
            {
                try
                {
                    CultureInfo provider = CultureInfo.InvariantCulture;

                    out_endDate = DateTime.ParseExact(txt_endDate.Text, "dd-MM-yyyy", provider);
                    if (!txt_endTime.Text.Trim().Equals(string.Empty))
                    {
                        out_endDate = out_endDate.Value.AddMinutes(txt_endTime.Text.GetTotalMinutes());
                    }

                    if (out_startDate.CompareTo(out_endDate.Value) > 0)
                    {
                        Messages.ShowWarning(Localization.GetString("ValidationEndDateInferior", this.LocalResourceFile));
                        return false;
                    }
                }
                catch (Exception)
                {
                    Messages.ShowWarning(Localization.GetString("ValidationInvalidEndDate", this.LocalResourceFile));
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Fills the language data into the respective controls
        /// </summary>
        private void FillLanguages()
        {
            lt_timeEntriesHistory.Text = Localization.GetString("lt_timeEntriesHistory", this.LocalResourceFile);
            chk_billable.Text = Localization.GetString("chk_billable", this.LocalResourceFile);
            btn_addTimeEntry.Text = Localization.GetString("btn_addTimeEntry", this.LocalResourceFile);
            btn_clearTimeEntry.Text = Localization.GetString("btn_clearTimeEntry", this.LocalResourceFile);
        }

        /// <summary>
        /// Gets the task time entries and binds them into the respective controls
        /// </summary>
        /// <param name="taskId"> the task to collect time entries from</param>
        private void BindTaskTime(int taskId)
        {
            //fill existing task comments
            using (UnitOfWork uof = new UnitOfWork(PortalId, ModuleId))
            {
                TaskTimeController taskTimeController = new TaskTimeController(uof, taskId);
                FillTaskTimeEntries(uof, taskTimeController);
            }
        }

        /// <summary>
        /// Fills the list view of time entries controller
        /// </summary>
        /// <param name="uof">unit of work</param>
        /// <param name="taskTimeController">task time controller</param>
        private void FillTaskTimeEntries(UnitOfWork uof, TaskTimeController taskTimeController)
        {
            lst_timeEntries.DataSource = taskTimeController.GetAll();
            lst_timeEntries.DataBind();
        }

        #endregion "Aux Functions"
    }
}